#include <stdlib.h>

#include <windows.h>

#include "lib.h"
#include "frame.h"
#include "bitmap.h"

pCFrame
newCFrame(HWND hWnd)
{
	pCFrame This = (pCFrame)malloc(sizeof(CFrame));
	if (This && !CFrameConstruct(This, hWnd))
	{
		free(This);
		This = (pCFrame)0;
	}
	return This;
}

pCFrame
newCFrame(int32 width, int32 height)
{
	pCFrame This = (pCFrame)malloc(sizeof(CFrame));
	if (This && !CFrameConstruct(This, width, height))
	{
		free(This);
		This = (pCFrame)0;
	}
	return This;
}

void	
deleteCFrame(pCFrame This)
{
	if (This)
	{
		CFrameDestruct(This);
		free(This);
	}
}

bool8		
CFrameConstruct(pCFrame This, HWND hWnd)
{
	RECT rect;

	GetClientRect(hWnd, &rect);

	return CFrameConstruct(This, rect.right, rect.bottom);
}


bool8		
CFrameConstruct(pCFrame This, int32 width, int32 height)
{
	This->chOldBmp = (HBITMAP)0;

	This->cDC = CreateCompatibleDC(NULL);
	if (!This->cDC)
		return false;

	This->cFrame = newCBitmapFrame(width, height, This->cDC);
	if (!This->cFrame)
	{
		DeleteDC(This->cDC);
		return false;
	}

	This->chOldBmp = (HBITMAP)SelectObject(This->cDC, CBitmapHBmp(This->cFrame));

	This->cSize.x = CBitmapWidth(This->cFrame);
	This->cSize.y = CBitmapHeight(This->cFrame);

	return true;
}

void		
CFrameDestruct(pCFrame This)
{
	SelectObject(This->cDC, This->chOldBmp);
	This->chOldBmp = (HBITMAP)0;

	deleteCBitmap(This->cFrame);
	This->cFrame = (pCBitmap)0;

	DeleteDC(This->cDC);
	This->cDC = (HDC)0;
}

void		
CFrameClear(pCFrame This)
{
	if (This)
		CBitmapClear(This->cFrame);
}

void	
CFrameClearRect(pCFrame This, int32 Left, int32 Top,
	int32 Right, int32 Bottom)
{
	if (This)
		CBitmapClearRect(This->cFrame, Left, Top, Right, Bottom);
}

void	
CFrameFillRect(pCFrame This, int32 Left, int32 Top,
			int32 Right, int32 Bottom, COLORSIZE Color)
{
	if (This)
		CBitmapFillRect(This->cFrame, Left, Top, Right, Bottom, Color);
}

void	
CFrameGetRect(pCFrame This, int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap dest)
{
	if (This)
		CBitmapBitmapBltSection(dest, 0, 0, sx, sy, sw, sh, This->cFrame);
}

void	
CFrameBitmapBlt(pCFrame This, int32 DestX, int32 DestY, pCBitmap Src)
{
	if (This)
		CBitmapBitmapBlt(This->cFrame, DestX, DestY, Src);
}

void			
CFrameBitmapBltSection(pCFrame This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap Src)
{
	if (This)
		CBitmapBitmapBltSection(This->cFrame, dx, dy, sx, sy, sw, sh, Src);
}

void	
CFrameTransparentBitmapBlt(pCFrame This, int32 DestX, int32 DestY,
	pCBitmap Src)
{
	if (This)
		CBitmapTransparentBitmapBlt(This->cFrame, DestX, DestY, Src);
}


void			
CFrameTransparentBitmapBltSection(pCFrame This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap Src)
{
	if (This)
		CBitmapTransparentBitmapBltSection(This->cFrame,
			dx, dy, sx, sy, sw, sh, Src);
}

void	
CFrameTransparentBitmapScaleBlt(pCFrame This,
	int32 dx, int32 dy, int32 dw, int32 dh, pCBitmap Src)
{
	// Now we really can transparently stretch an image
	if (This)
		TransparentStretchBlt (This->cFrame, dx, dy, Src, dw, dh);
}


// Alpha blit to the frame a bitmap using a constant alpha value
void
CFrameCAlphaBlt(pCFrame This, int32 dx, int32 dy, pCBitmap Src, uint8 alpha)
{
	if (This)
		CBitmapAlphaBitmapBltSection(This->cFrame, dx, dy, 0, 0, CBitmapWidth(Src), CBitmapHeight(Src), Src, alpha);
}


// kharmon.  05-08-06.  Improved Graphics.  
// Made this a function template that could thus handle 16 and 24 bit pixel types.
template <class PixelType> void CFrameLine_X(pCFrame This, int32 x1, int32 y1, int32 x2, int32 y2, PixelType Color)
{
	if (!This)
		return;

	int32	deltax, deltay;
	int32	d, dinc1, dinc2;
	int32	xinc1, xinc2;
	int32	yinc1, yinc2;
	PixelType*	ptr;
	int32	pyinc1, pyinc2;


	// Simple boundry check (convoluted yes...but, condensed).
	x1 = MIN(MAX(x1, 0), (CFrameWidth(This) - 1));
	y1 = MIN(MAX(y1, 0), (CFrameHeight(This) - 1));
	x2 = MIN(MAX(x2, 0), (CFrameWidth(This) - 1));
	y2 = MIN(MAX(y2, 0), (CFrameHeight(This) - 1));

	deltax = ABS(x2 - x1);
	deltay = ABS(y2 - y1);

	if (deltax >= deltay)
	{
		d = (deltay << 1) - deltax;
		dinc1 = deltay << 1;
		dinc2 = (deltay - deltax) << 1;
		xinc1 = 1;
		xinc2 = 1;
		yinc1 = 0;
		yinc2 = 1;
		pyinc1 = 0;
		pyinc2 = CFrameRowBytes(This);
	}
	else
	{
		d = (deltax << 1) - deltay;
		dinc1 = deltax << 1;
		dinc2 = (deltax - deltay) << 1;
		xinc1 = 0;
		xinc2 = 1;
		yinc1 = 1;
		yinc2 = 1;
		pyinc1 = CFrameRowBytes(This);
		pyinc2 = CFrameRowBytes(This);
	}

	if (x1 > x2)
	{
		xinc1 = -xinc1;
		xinc2 = -xinc2;
	}
	if (y1 > y2)
	{
		yinc1 = -yinc1;
		yinc2 = -yinc2;
		pyinc1 = -pyinc1;
		pyinc2 = -pyinc2;
	}

	CFrameLock(This);

	ptr = (PixelType *)(CFrameBits(This) + (CFrameRowBytes(This) * y1) + (x1*(getBitsPerPixel()/8)));

	while (1)
	{
		*ptr = Color;

		if (x1 == x2 && y1 == y2)
			break;

		if (d <= 0)
		{
			d = d + dinc1;
			x1 = x1 + xinc1;
			y1 = y1 + yinc1;
			ptr = ptr + xinc1 + pyinc1/sizeof(*ptr);
		}
		else
		{
			d = d + dinc2;
			x1 = x1 + xinc2;
			y1 = y1 + yinc2;
			ptr = ptr + xinc2 + pyinc2/sizeof(*ptr);
		}
	}

	CFrameUnlock(This);
}



void
CFrameLine(pCFrame This, int32 x1, int32 y1, int32 x2, int32 y2, COLORSIZE Color)
{
    // kharmon.  05-08-06.  Improved Graphics.  
    // This never seems to get called, but I'll go ahead and update it to work with
    // 16 and 24 bit graphic modes anyway.
    if(getBitsPerPixel()==16)
    {
        CFrameLine_X(This, x1, y1, x2, y2, (uint16) Color);
    }
    else
    {
        RGBTRIPLE lineColor;
        lineColor.rgbtRed   = GETR(Color);
        lineColor.rgbtGreen = GETG(Color);
        lineColor.rgbtBlue  = GETB(Color);

        CFrameLine_X(This, x1, y1, x2, y2, lineColor);
    }
}



// These methods use the new BitmapBlt(Section) code.  BitmapBlt(Section) uses the bitmap 's properties
// to select the appropriate blitter  - alpha, transparent or blit.
void			
CFrameBltSection(pCFrame This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap Src)
{
	if (This)
		BitmapBltSection(This->cFrame, dx, dy, sx, sy, sw, sh, Src);
}

void			
CFrameBlt(pCFrame This, int32 dx, int32 dy, pCBitmap Src)
{
	if (This)
		BitmapBlit(This->cFrame, dx, dy, Src);
}

